# --------------------------------------------------------------------------------
#  NoiseTube Web application
#
#  Copyright (C) 2008-2010 SONY Computer Science Laboratory Paris
#  Portions contributed by Vrije Universiteit Brussel (BrusSense team), 2008-2013
# --------------------------------------------------------------------------------
#  This library is free software; you can redistribute it and/or modify it under
#  the terms of the GNU Lesser General Public License, version 2.1, as published
#  by the Free Software Foundation.
#
#  This library is distributed in the hope that it will be useful, but WITHOUT
#  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
#  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
#  details.
#
#  You should have received a copy of the GNU Lesser General Public License along
#  with this library; if not, write to:
#    Free Software Foundation, Inc.,
#    51 Franklin Street, Fifth Floor,
#    Boston, MA  02110-1301, USA.
#
#  Full GNU LGPL v2.1 text: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
#  NoiseTube project source code repository: http://code.google.com/p/noisetube
# --------------------------------------------------------------------------------
#  More information:
#   - NoiseTube project website: http://www.noisetube.net
#   - Sony Computer Science Laboratory Paris: http://csl.sony.fr
#   - VUB BrusSense team: http://www.brussense.be
# --------------------------------------------------------------------------------

class UsersController < ApplicationController
  # Be sure to include AuthenticationSystem in Application Controller instead
  include AuthenticatedSystem

  caches_action :index

  before_filter :find_user, :except => [:new, :index, :create, :realtime, :reset_password, :forgot_password, :change_password]
  before_filter :authenticate_user, :only => [:edit, :deltrack, :update, :uploaddata, :uploadxml, :change_password]
  before_filter :login_redirect, :only  => [:show]

  respond_to :jpg

  # render new.rhtml
   def new
     @user = User.new
       location=get_location_by_ip
     @user[:location]= location
   end
 
  def create
    logout_keeping_session!

    #get the location
    location = params[:user][:location]

     user_hash=params[:user].except(:location)

      unless user_hash.nil?
        @user = User.new(user_hash)

        if request.ip == "127.0.0.1" || verify_recaptcha
          @user.public=true #default

          s = Geocoder.search(location)

          if s.blank? || s[0].city.nil?
            @user.errors.add(:location, "The home town you specified was not found")
          else

            city=City.build_city(s)
            @user.city=city

          end

          success = @user.save

          if success && @user.errors.empty?
            # Protects against session fixation attacks, causes request forgery
            # protection if visitor resubmits an earlier form using back button.
            # Uncomment if you understand the tradeoffs. reset session
            self.current_user = @user # !! now logged in
            flash[:notice] = "Your are now registered! We suggest to put a picture of you.<br/>You can now download the mobile application"

            #expires_page(:controller => "/users", :action => "index") #TODO this doesn't work (causes crash), fix it
            redirect_to "/download"
          else
            error_string = ""
            #build the error string
            unless (@user.errors.messages.blank?)
               @user.errors.each { |key, msg|
                   error_string << "<br/> <b>#{key}</b>: #{msg}  "
               }
            end
            flash.now[:error]  = "<b>We couldn't set up your account. The following errors occurred:</b> #{error_string}"
            render :action => 'new'
          end
        else
          @user.errors[:base] << ""
          flash.now[:error]  = "<b>We couldn't set up your account. ReCAPTCHA is not correct, please try again."
          render :action => 'new'
        end
      end
  end

  def show
    respond_to do |format|

      # only public track
      clause="public=true" unless @user==current_user

      format.html {
        @summary={}
        @summary[:last_activity]=@user.measures.find(:last).made_at unless @user.measures.find(:last).nil?
        @summary[:measures_size]=@user.measures_size
        @summary[:tags_assignement_size]= @user.tags_size #@user.owned_taggings.count
        @tags=@user.prominent_tags.all

        @tracks=Track.where("user_id = #{@user.id}").paginate(:conditions=>clause, :per_page => 10, :order=>"tracks.created_at desc", :page => params[:page])
        # #@onload="initialize();" #@onunload="GUnload();"
      }

      format.rss{
        @tracks=@user.tracks.all(:conditions=>clause, :order=>"tracks.created_at desc", :limit=>10)
        render :layout=>false,:mimetype =>:rss
      }

      format.js {
        render :update do |page|
          p params
          @tracks=@user.tracks.paginate(:all,:conditions=>clause, :per_page => 10, :order=>"tracks.created_at desc", :page => params[:page])
          page.replace_html 'results', :partial => 'track_list'
        end
      }
      format.jpg{
          u = User.find(params[:id])
         if FileTest.exists?("#{Rails.root}#{u.image_url.thumb.to_s}")
            redirect_to u.image_url.thumb.to_s, mimetype: :jpg
         else
           redirect_to '/images/default_user.gif'
         end
      }
    end
  end

  def index
    users=User.select("distinct users.*").joins(:tracks).where("tracks.processed=true").order("users.updated_at desc").limit(10)
    @users=[]
    users.each {|user|
      tags= user.recent_taggings
      @users<<{:user=>user , :tags=>tags}
    }
  end

  def activate
    logout_keeping_session!
    user = User.find_by_activation_code(params[:activation_code]) unless params[:activation_code].blank?
    case
    when (!params[:activation_code].blank?) && user && !user.active?
      user.activate!
      redirect_to '/login', :notice => "Signup complete! Please sign in to continue."
    when params[:activation_code].blank?
      redirect_back_or_default('/', :flash => { :error => "The activation code was missing.  Please follow the URL from your email." })
    else 
      redirect_back_or_default('/', :flash => { :error  => "We couldn't find a user with that activation code -- check your email? Or maybe you've already activated -- try signing in." })
    end
  end


  ################ ACCOUNT INFORMATION ###################

  def edit
    city = City.find_by_id(@user.city_id)
    @user[:location] = "#{city.name}, #{city.country}"
    @user
  end

  def find_user
    if params[:id] =~ /^\d*$/
      @user = User.find(params[:id])
    else
      unless (@user = User.find_by_login(params[:id]))
        raise ActiveRecord::RecordNotFound
      end
    end
  end
  def update

    location = params[:user][:location]
    user_hash = params[:user].except(:location)

    s = Geocoder.search(location)

    if s.blank? || s[0].city.nil?
      @user.errors.add(:location, "The location you specified was not found")
    else

      city=City.build_city(s)
      @user.city=city
    end

    if @user.update_attributes(user_hash)
      flash[:notice] ="Profile saved"
      #expire_photo(@user)
      redirect_to(@user)
    else
      flash[:error] ="Error"
      render :action => 'edit'
    end
  end

  ############# AUTHENTICATE USER #######################
  def authenticate_user
    redirect_to root_url unless logged_in? && @user==current_user
  end

  def login_redirect
    unless logged_in?
      session[:return_to] ||= request.fullpath
     redirect_to login_url , notice: "Login first to view the page"
    end
  end

  # ################## PASSWORD STUFF #######################

  def change_password
    return unless request.post?
    if User.authenticate(current_user.login, params[:old_password])
      if (params[:password] == params[:password_confirmation]) &&
                !params[:password_confirmation].blank?
        current_user.password_confirmation = params[:password_confirmation]
        current_user.password = params[:password]

        if current_user.save
          flash[:notice] = "Password successfully updated"
          redirect_to profile_url(current_user.login)
        else
          flash[:alert] = "Password not changed"
        end
      else
        flash[:alert] = "New Password mismatch"
        @old_password = params[:old_password]
      end
    else
      flash[:alert] = "Old password incorrect"
    end
  end

  def forgot_password
    return unless request.post?
    if @user = User.find_by_email(params[:user][:email])
      @user.forgot_password
      success = @user && @user.save!
      if success
        logger.info("Archving sending of forgot email for #{@user.login}....")
        @user.emailer_callback #send the email asynchronously
        logger.info("...archived email for #{@user.login}.")
        redirect_to login_url
        flash[:notice] = "A password reset link will be sent to your email address. Please check your email after 15 minutes."
      else
        logger.error "Error when modifying forgot_password for user #{@user.try(:login)}"
        redirect_to login_url
        flash[:error] = "Something went wrong, please try your action again in a few minutes..."
      end
    else
      redirect_to login_url
      flash[:error] = "Could not find a user with that email address"
    end
  end

  def reset_password
    @user = User.find_by_password_reset_code(params[:id])
    return if @user unless params[:user]
    unless params[:user].blank?
      if ((params[:user][:password] && params[:user][:password_confirmation]) && !params[:user][:password_confirmation].blank?)
        self.current_user = @user #for the next two lines to work
        current_user.password_confirmation = params[:user][:password_confirmation]
        current_user.password = params[:user][:password]
        @user.reset_password
        flash[:notice] = "You changed your password successfully"
        redirect_back_or_default('/')
      else
        flash[:alert] = "Password mismatch"
      end
    else
      redirect_to("/")
    end

  end

  #############  UPLOAD DATA ###############

  def uploaddata #view page

  end

  #@param xml_file - the xml file
  def uploadxml #process the data
    begin
      # get the uploaded file and read it...
      uploaded_file = params[:xml_file]
      xml_data = uploaded_file.read if uploaded_file.respond_to? :read

      # do we have data from the file?
      unless request.post? and xml_data
        redirect_to root_url
        return
      end

      # append session closing tag if needed:
      closing_tag = "</NoiseTube-Mobile-Session>"
      xml_data += closing_tag if xml_data.rindex(closing_tag).nil?

      # parse the data using REXML...
      xml_doc = REXML::Document.new(xml_data)
      track=Track.from_xml(xml_doc, @user)
      #track.process (handled by separate process)

      # redirect
      logger.info ("Uploading measurements from xml file for #{current_user.login}..... ")
      flash[:upload_notice] = "A track with a total of #{track.measures.size} measures was added. Thanks for your contribution!"

      redirect_to(@user)
    rescue Exception => exc
      logger.error("Error processing uploaded track (XML file): #{exc.message}")
      flash[:error] = "Upload failed, please mail the file to support@noisetube.net"
      render :action => 'uploaddata'
    end
  end



end
